package com.listeningframework.boot.autoconfigure.template.sitemesh;

import org.apache.commons.collections.MapUtils;
import org.sitemesh.builder.SiteMeshFilterBuilder;
import org.sitemesh.config.ConfigurableSiteMeshFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map.Entry;

/**
 * The Configuration In Order To use Sitemesh Decorator Mapping
 *
 * @author lixining
 * @version $Id: ListeningSiteMeshConfiguration.java, v 0.1 2015年4月17日 下午5:22:37 lixining Exp $
 */
@Configuration
@ConditionalOnClass(ConfigurableSiteMeshFilter.class)
@EnableConfigurationProperties(ListeningSitemeshProperties.class)
public class ListeningSitemeshConfiguration {
    /**
     * Match All Resources Expression
     */
    private static final String PATH_MATCH_ALL = "/**";
    private static final String PATH_MATCH_LOGIN = "/login";
    private static final String FILE_SEPRATOR = "/";
    private static final String DEFAULT_SITEMESH_LOGIN = "sitemesh-login.html";
    private static final String DEFAULT_SITEMESH_MAIN = "sitemesh-default.html";

    /**
     * Register SiteMesh For the Container
     *
     * @param siteMeshProperties 配置参数
     * @return FilterRegistrationBean
     */
    @Bean(name = "sitemesh")
    public FilterRegistrationBean listeningSiteMeshFilter(ListeningSitemeshProperties siteMeshProperties) {
        ListeningSiteMeshFilter listeningSiteMesh = new ListeningSiteMeshFilter(siteMeshProperties);
        return new FilterRegistrationBean(listeningSiteMesh);
    }

    /**
     * Override the ConfigurableSiteMeshFilter, With Method applyCustomConfiguration
     * To Custom the Mappings by Java Code
     *
     * @author listening
     * @version $Id: SiteMeshConfiguration.java, v 0.1 2015年4月9日 下午9:28:31 listening Exp $
     */
    public static class ListeningSiteMeshFilter extends ConfigurableSiteMeshFilter {
        private ListeningSitemeshProperties listeningProperties;

        private ListeningSiteMeshFilter(ListeningSitemeshProperties listeningProperties) {
            this.listeningProperties = listeningProperties;
        }

        /**
         * @see org.sitemesh.config.ConfigurableSiteMeshFilter#applyCustomConfiguration(org.sitemesh.builder.SiteMeshFilterBuilder)
         */
        @Override
        protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {
            builder.setMimeTypes("text/html", "application/xhtml+xml");
            builder.addExcludedPath(SitemeshMappingController.PREFIX_MAPPING + PATH_MATCH_ALL);

            LinkedHashMap<String, String> decoratorsMap = listeningProperties.getDecorator();
            if (decoratorsMap == null || MapUtils.isEmpty(decoratorsMap)) {
                addDecorator(builder, PATH_MATCH_LOGIN, DEFAULT_SITEMESH_LOGIN);
                addDecorator(builder, PATH_MATCH_ALL, DEFAULT_SITEMESH_MAIN);
                return;
            }
            for (Entry<String, String> entry : decoratorsMap.entrySet()) {
                String entryKey = entry.getKey();
                String key = entryKey.startsWith(FILE_SEPRATOR) ? entryKey : (FILE_SEPRATOR + entryKey);
                addDecorator(builder, key, entry.getValue());
            }
        }

        /**
         * get decorator mapping path
         *
         * @param decorator 装饰器
         * @return string
         */
        private String getDecoratorPage(String decorator) {
            return SitemeshMappingController.PREFIX_MAPPING + FILE_SEPRATOR + decorator;
        }

        /**
         * add decorator for pattern
         *
         * @param builder SiteMeshFilterBuilder
         * @param pattern 类型
         * @param mapping 映射地址
         */
        private void addDecorator(SiteMeshFilterBuilder builder, String pattern, String mapping) {
            builder.addDecoratorPath(pattern, getDecoratorPage(mapping));
        }
    }
}
